<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="robots" content="noodp" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
        <title>《Flutter应用集成浅析》 - Lucklyの博客 - 在阅读中遇见自己</title><meta name="Description" content="早起的年轻人做的网站"><meta property="og:title" content="《Flutter应用集成浅析》" />
<meta property="og:description" content="
本文主要简单分析下 Flutter 如何集成到现有 Android 应用中。
" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://luckly.work/flutter%E5%BA%94%E7%94%A8%E9%9B%86%E6%88%90%E6%B5%85%E6%9E%90/" />
<meta property="og:image" content="https://luckly.work/logo.png"/>
<meta property="article:published_time" content="2021-07-31T21:18:50+08:00" />
<meta property="article:modified_time" content="2021-07-31T21:18:50+08:00" />
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="https://luckly.work/logo.png"/>

<meta name="twitter:title" content="《Flutter应用集成浅析》"/>
<meta name="twitter:description" content="
本文主要简单分析下 Flutter 如何集成到现有 Android 应用中。
"/>
<meta name="application-name" content="LoveIt">
<meta name="apple-mobile-web-app-title" content="LoveIt"><meta name="theme-color" content="#ffffff"><meta name="msapplication-TileColor" content="#da532c"><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
        <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5"><link rel="manifest" href="/site.webmanifest"><link rel="canonical" href="https://luckly.work/flutter%E5%BA%94%E7%94%A8%E9%9B%86%E6%88%90%E6%B5%85%E6%9E%90/" /><link rel="prev" href="https://luckly.work/flutter-sizedoverflowbox-%E7%AE%80%E4%BB%8B%E5%8F%8A%E6%A1%88%E4%BE%8B/" /><link rel="next" href="https://luckly.work/futurebuilder%E4%B8%8Estreambuilder/" /><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.min.css"><link rel="stylesheet" href="/css/style.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.13.0/css/all.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css@3.7.2/animate.min.css"><script type="application/ld+json">
    {
        "@context": "http://schema.org",
        "@type": "BlogPosting",
        "headline": "《Flutter应用集成浅析》",
        "inLanguage": "zh-CN",
        "mainEntityOfPage": {
            "@type": "WebPage",
            "@id": "https:\/\/luckly.work\/flutter%E5%BA%94%E7%94%A8%E9%9B%86%E6%88%90%E6%B5%85%E6%9E%90\/"
        },"image": [{
                            "@type": "ImageObject",
                            "url": "https:\/\/luckly.work\/images\/Apple-Devices-Preview.png",
                            "width":  3200 ,
                            "height":  2048 
                        }],"genre": "posts","keywords": "flutter","wordcount":  3981 ,
        "url": "https:\/\/luckly.work\/flutter%E5%BA%94%E7%94%A8%E9%9B%86%E6%88%90%E6%B5%85%E6%9E%90\/","datePublished": "2021-07-31T21:18:50+08:00","dateModified": "2021-07-31T21:18:50+08:00","license": "This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.","publisher": {
            "@type": "Organization",
            "name": "xxxx","logo": {
                    "@type": "ImageObject",
                    "url": "https:\/\/luckly.work\/images\/avatar.png",
                    "width":  528 ,
                    "height":  560 
                }},"author": {
                "@type": "Person",
                "name": "早起的年轻人"
            },"description": ""
    }
    </script></head>
    <body header-desktop="fixed" header-mobile="auto"><script type="text/javascript">(window.localStorage && localStorage.getItem('theme') ? localStorage.getItem('theme') === 'dark' : ('auto' === 'auto' ? window.matchMedia('(prefers-color-scheme: dark)').matches : 'auto' === 'dark')) && document.body.setAttribute('theme', 'dark');</script>

        <div id="mask"></div><div class="wrapper"><div class="logo-wrapper">
  <a href="/%20/" class="logo">Lucklyの博客 - 在阅读中遇见自己</a>
</div>

<nav class="site-navbar">
  <ul id="menu" class="menu">
    <li class="menu-item">
      <a class="menu-item-link" href="/posts/">所有文章</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/categories/flutter/">Flutter</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/categories/read/">读书笔记</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/categories/go/">Go</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/tags/">标签</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/categories/">分类</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/about/">关于</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="https://github.com/ITmxs">Github</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/friend/">友链</a>
    </li>
  </ul>
</nav><main class="main">
                <div class="container"><div class="toc" id="toc-auto">
            <h2 class="toc-title">目录</h2>
            <div class="toc-content" id="toc-content-auto"></div>
        </div><article class="page single"><h1 class="single-title animated flipInX">《Flutter应用集成浅析》</h1><div class="post-meta">
            <div class="post-meta-line"><span class="post-author"><a href="/" title="Author" rel=" author" class="author"><i class="fas fa-user-circle fa-fw"></i>早起的年轻人</a></span>&nbsp;<span class="post-category">收录于 <a href="/categories/flutter/"><i class="far fa-folder fa-fw"></i>Flutter</a></span></div>
            <div class="post-meta-line"><i class="far fa-calendar-alt fa-fw"></i>&nbsp;<time datetime="2021-07-31">2021-07-31</time>&nbsp;<i class="fas fa-pencil-alt fa-fw"></i>&nbsp;约 3981 字&nbsp;
                <i class="far fa-clock fa-fw"></i>&nbsp;预计阅读 8 分钟&nbsp;</div>
        </div><div class="featured-image"><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png, https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png"
        title="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png" /></div><div class="details toc" id="toc-static"  kept="">
                <div class="details-summary toc-title">
                    <span>目录</span>
                    <span><i class="details-icon fas fa-angle-right"></i></span>
                </div>
                <div class="details-content toc-content" id="toc-content-static"><nav id="TableOfContents">
  <ul>
    <li><a href="#前言">前言</a></li>
    <li><a href="#产物集成">产物集成</a></li>
    <li><a href="#源码集成">源码集成</a></li>
    <li><a href="#buildgradle">build.gradle</a></li>
    <li><a href="#fluttergradlehttpsgithubcomflutterflutterblobmasterpackagesflutter_toolsgradlefluttergradle"><a href="https://github.com/flutter/flutter/blob/master/packages/flutter_tools/gradle/flutter.gradle">flutter.gradle</a></a>
      <ul>
        <li><a href="#添加-flutter-task">添加 Flutter Task</a>
          <ul>
            <li><a href="#addflutterdeps">addFlutterDeps</a></li>
            <li><a href="#configureplugins">configurePlugins</a></li>
          </ul>
        </li>
        <li><a href="#添加-flutter-dependency">添加 Flutter Dependency</a></li>
      </ul>
    </li>
    <li><a href="#实践">实践</a>
      <ul>
        <li><a href="#编译失败-cause-assert-appproject--null">编译失败 Cause: assert appProject != null</a></li>
        <li><a href="#找不到-libflutterso-或-libappso">找不到 <code>libflutter.so</code> 或 <code>libapp.so</code></a></li>
      </ul>
    </li>
    <li><a href="#参考">参考</a></li>
  </ul>
</nav></div>
            </div><div class="content" id="content"><blockquote>
<p>本文主要简单分析下 Flutter 如何集成到现有 Android 应用中。</p>
</blockquote>
<h1 id="前言">前言</h1>
<p>截止目前 Flutter (1.12.13+hotfix.5)，集成到 Android 应用已经非常简单了。</p>
<blockquote>
<p>Flutter can be embedded into your existing Android application piecemeal, as a source code Gradle subproject or as AARs.</p>
</blockquote>
<p>无非两种集成方式：源码集成或 AAR 产物集成。，这里不再赘述，仅做简单总结。</p>
<ul>
<li>Android Studio 3.6 + Flutter IntelliJ plugin (version 42及以上) 可以方便快速地自动集成 Flutter 模块</li>
<li>Flutter 的 Android 引擎使用 Java 8 特性，所以要记得开启 1.8 兼容，否则会提示 “default interface methods” 问题</li>
<li><a href="https://flutter.dev/docs/development/add-to-app/android/project-setup#option-b---depend-on-the-modules-source-code" target="_blank" rel="noopener noreffer">源码集成</a> 时注意 Android 工程和 Flutter 工程在同级目录下</li>
<li>注意编译模式及CPU架构，不匹配的话会出现找不到 <code>libflutter.so</code> 的问题</li>
<li>Flutter 的 AOT(ahead of time) 编译产物只支持 <code>armeabi-v7a</code> 和 <code>arm64-v8a</code>，x86 下可进行 debug (Just-In-Time, JIT 模式)，但不能安装 release 包</li>
</ul>
<h1 id="产物集成">产物集成</h1>
<p>产物集成相比源码集成更简单。主要步骤如下，具体过程可参考<a href="https://flutter.dev/docs/development/add-to-app/android/project-setup#create-a-flutter-module" target="_blank" rel="noopener noreffer">官方文档</a>。</p>
<p>第一步，生成 AAR。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">cd flutter_project
flutter build aar
</code></pre></td></tr></table>
</div>
</div><p>缺省编译所有模式下的产物，包括 debug, profile 和 release。不想编译 profile 模式产物的话，加上 <code>--no-profile</code> 即可。</p>
<p>另外注意编译 AAR 有限制，仅能为 plugin 或 module 工程编译 AAR 产物，否则提示如下错误。</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg"
        title="-w541" /></p>
<p>第二步，添加产物仓库及依赖。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">repositories {
  // AAR 产物本地仓库
  maven {
      url &#39;/Users/user/wd/xyz/build/host/outputs/repo&#39;
  }
  // Flutter 框架官方仓库
  maven {
      url &#39;http://download.flutter.io&#39;
  }
}
dependencies {
  debugImplementation &#39;com.tencent.xyz:flutter_debug:1.0
  profileImplementation &#39;com.tencent.xyz:flutter_profile:1.0
  releaseImplementation &#39;com.tencent.xyz:flutter_release:1.0
}
</code></pre></td></tr></table>
</div>
</div><p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg"
        title="-w700" /></p>
<h1 id="源码集成">源码集成</h1>
<p>第一步，创建 Flutter 项目。在 host app 的同级目录下创建 <code>my_flutter</code> 项目：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">$ cd some/path/
$ flutter create -t module --org com.example my_flutter
</code></pre></td></tr></table>
</div>
</div><p>第二步，引入 Flutter 项目并作为模块。在 host app 的 <code>settings.gradle</code> 文件中添加如下配置：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">...
setBinding(new Binding([gradle: this]))                                 // new
evaluate(new File(                                                      // new
  settingsDir.parentFile,                                               // new
  &#39;my_flutter/.android/include_flutter.groovy&#39;                          // new
)) 
include &#39;:my_flutter&#39;
project(&#39;:my_flutter&#39;).projectDir = new File(&#39;../my_flutter&#39;)
</code></pre></td></tr></table>
</div>
</div><p>这段配置的作用不妨视作黑魔法，其作用如下：</p>
<ul>
<li>将 <code>my_flutter</code> <strong>Flutter Project</strong> 作为名为 <code>:flutter</code> 的 <strong>Android Library Module</strong>，引入到当前 <strong>Android Project</strong></li>
<li>查找并保存 <code>my_flutter</code> 依赖的 Flutter 插件</li>
</ul>
<p>第三步，添加对 <code>:flutter</code> module 的依赖。在 host app 的 <code>build.gradle</code> 中加上以下配置：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">dependencies {
  implementation project(&#39;:flutter&#39;)
}
</code></pre></td></tr></table>
</div>
</div><p>以上是手工操作步骤。在 Android 3.6 中可以自动操作，同样也会产生跟上面相同的配置。</p>
<p>Android Studio 3.6 中打开 host app，并新建一个 Flutter Module：</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg"
        title="-w633" /></p>
<p>创建完成后生成的配置如下：</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg"
        title="-w1185" /></p>
<p>可见，无论手工操作还是自动操作，源码集成的关键在于这几个脚本：</p>
<ul>
<li><del>my_flutter/.android/include_flutter.groovy</del> - 黑魔法，用于在 Android 工程引入 Flutter 工程，我们略过</li>
<li><code>my_flutter/.android/Flutter/build.gradle</code> - 这个脚本决定 Flutter 工程如何构建，它引入 Flutter SDK 中的 <code>flutter.gradle</code> 脚本</li>
<li><code>&lt;Flutter SDK&gt;/packages/flutter_tools/gradle/flutter.gradle</code> - 集成 Flutter 工程的核心</li>
</ul>
<p>接下来我将分析 <code>build.gradle</code> 和 <code>flutter.gradle</code> 两个脚本是如何将 Flutter 集成到 Android 应用的。</p>
<h1 id="buildgradle">build.gradle</h1>
<p>先来分析 <code>my_flutter/.android/Flutter/build.gradle</code>。</p>
<p>第一步，加载并解析 <code>.android</code> 目录下的 <code>local.properties</code> 文件。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">// 加载 .android 目录下的 local.properties 文件
def localProperties = new Properties()
def localPropertiesFile = new File(buildscript.sourceFile.parentFile.parentFile, &#39;local.properties&#39;)
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader(&#39;UTF-8&#39;) { reader -&gt;
        localProperties.load(reader)
    }
}

// 解析 flutter.sdk(必选)
def flutterRoot = localProperties.getProperty(&#39;flutter.sdk&#39;)
if (flutterRoot == null) {
    throw new GradleException(&#34;Flutter SDK not found. Define location with flutter.sdk in the local.properties file.&#34;)
}

// 解析 flutter.versionCode(可选)
def flutterVersionCode = localProperties.getProperty(&#39;flutter.versionCode&#39;)
if (flutterVersionCode == null) {
    flutterVersionCode = &#39;1&#39;
}

// 解析 flutter.versionName(可选)
def flutterVersionName = localProperties.getProperty(&#39;flutter.versionName&#39;)
if (flutterVersionName == null) {
    flutterVersionName = &#39;1.0&#39;
}
</code></pre></td></tr></table>
</div>
</div><p>第二步，引入 <code>flutter.gradle</code> 脚本并通过 <code>flutter</code> 插件指定 <strong>Flutter Project</strong> 源码位置。<code>flutter</code> 插件来自 <code>flutter.gradle</code> 脚本中的 <code>FlutterPlugin</code>。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">apply from: &#34;$flutterRoot/packages/flutter_tools/gradle/flutter.gradle&#34;

...

// 指定的 Flutter 源码路径
flutter {
    source &#39;../..&#39;
}

...
</code></pre></td></tr></table>
</div>
</div><h1 id="fluttergradlehttpsgithubcomflutterflutterblobmasterpackagesflutter_toolsgradlefluttergradle"><a href="https://github.com/flutter/flutter/blob/master/packages/flutter_tools/gradle/flutter.gradle" target="_blank" rel="noopener noreffer">flutter.gradle</a></h1>
<p>再来看 <code>&lt;Flutter SDK&gt;/packages/flutter_tools/gradle/flutter.gradle</code>。<code>flutter</code> 插件的具体实现在 <code>apply()</code> 方法。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">// 应用 FlutterPlugin
apply plugin: FlutterPlugin

// 定义名为 flutter 的 FlutterPlugin 插件
class FlutterPlugin implements Plugin&lt;Project&gt; {
    private Project project

    @Override
    void apply(Project project) {
        this.project = project
        // 创建名为 flutter 的 FlutterExtension
        project.extensions.create(&#34;flutter&#34;, FlutterExtension) 
        // 添加 Flutter Task
        project.afterEvaluate this.&amp;addFlutterTasks
        // 配置 APK。修改 project.android (android插件)的配置
        ...
        // 获取 Flutter 相关信息
        // 添加 Flutter Dependency
        project.android.buildTypes.each this.&amp;addFlutterDependencies
        project.android.buildTypes.whenObjectAdded this.&amp;addFlutterDependencies
    }
}
</code></pre></td></tr></table>
</div>
</div><p><code>apply()</code> 主要流程概括如下：</p>
<ul>
<li>创建 FlutterExtension。这个插件很简单，只包括
<ul>
<li><code>source</code>(源码路径)</li>
<li><code>target</code>(Dart入口，通常是 <code>lib/main.dart</code>)</li>
</ul>
</li>
<li><strong>添加 Flutter Task</strong></li>
<li>配置 APK
<ul>
<li>针对 Target Platform 生成 multiple APK 或 fat APK</li>
<li>配置 build type，例如是否压缩资源</li>
</ul>
</li>
<li>获取 Flutter 相关信息
<ul>
<li>本地 Flutter SDK 路径</li>
<li><code>flutter</code> 命令</li>
<li>引擎版本</li>
<li>引擎路径 (来自 <code>gradle.properties</code> 文件的 <code>local-engine-out</code> 属性 )</li>
</ul>
</li>
<li><strong>添加 Flutter Dependency</strong></li>
</ul>
<p>接下来我们挑重点说，</p>
<ul>
<li>添加 Flutter Task</li>
<li>添加 Flutter Dependency</li>
</ul>
<p>简单来说，添加 Flutter Task 是添加一些 Task 用于处理三类 Flutter 相关的资源，库、资源、插件：</p>
<ul>
<li>库 - 库是编译过程中生成jar文件和so文件。库文件应正确地打包到 AAR 或 APK</li>
<li>资源 - 资源是 <code>pubspec.yaml</code> 文件添加指定的各类资源，如图片、字体等。资源文件应正确地打包到 AAR 或 APK</li>
<li>插件 - 插件是 <code>pubspec.yaml</code> 文件添加的各种 Dart 库。插件的处理比较麻烦，一是某些插件包含原生Java或OC代码，二是插件之间有依赖关系</li>
</ul>
<p>而添加 Flutter Dependency 则是将 Flutter 框架(包括引擎)添加为 Android 工程的依赖，具体包括：</p>
<ul>
<li><code>flutter_embedding.jar</code> - Flutter Framework，即 <code>io.flutter.embedding.android.FlutterActivity</code> 所在的 Java 库</li>
<li><code>libflutter.so</code> - Flutter 引擎</li>
</ul>
<hr>
<p>跟以上流程相关的几个辅助方法：</p>
<ul>
<li><code>useLocalEngine()</code> - 判断是否使用本地 Flutter 引擎，来自 <code>gradle.properties</code> 文件的 <code>local-engine-repo</code> 属性</li>
<li><code>getTargetPlatforms</code> - 获取 Target Platform，来自 <code>gradle.properties</code> 文件的 <code>target-platform</code> 属性</li>
<li><code>shouldSplitPerAbi()</code> - 判断是否生成 multiple APK (即针对每种架构生成一个 APK，与之对应的是 fat APK)，来自 <code>gradle.properties</code> 文件的 <code>split-per-abi</code> 属性，缺省为 <code>false</code></li>
<li><code>getPluginList()</code> - 解析 <code>.flutter-plugins</code> 文件获取插件列表</li>
<li><code>getPluginDependencies()</code> - 解析 <code>.flutter-plugins-dependencies</code> 文件获取插件依赖</li>
</ul>
<hr>
<h2 id="添加-flutter-task">添加 Flutter Task</h2>
<p><code>addFlutterTasks()</code> 是最复杂的方法。精简后的代码如下：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">private void addFlutterTasks(Project project) {
    // 1. 参数检查
    ...
    // 2. 从 `gradle.properties` 获取各种参数
    ...
    // 3. 定义 addFlutterDeps 匿名方法
    def addFlutterDeps = { variant -&gt; 
    
    }
    ...
    // 4. 为所有 applicationVariants 或 libraryVariants 添加 Flutter 依赖
    if (project.android.hasProperty(&#34;applicationVariants&#34;)) {
        project.android.applicationVariants.all addFlutterDeps
    } else {
        project.android.libraryVariants.all addFlutterDeps
    }
    // 5. 配置插件依赖
    configurePlugins()
}
</code></pre></td></tr></table>
</div>
</div><ul>
<li>第3步和第4步处理库和资源</li>
<li>第5步处理插件</li>
</ul>
<h3 id="addflutterdeps">addFlutterDeps</h3>
<p>首先看第3步 <code>addFlutterDeps</code> 的创建。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">// 1. 创建 compileTask。FlutterTask 实际是对 flutter build 命令的包装
FlutterTask compileTask = project.tasks.create(name: taskName, type: FlutterTask) {}

// 2. 创建 packFlutterAppAotTask。将第1步中的编译结果打包成 libs.jar 文件
Task packFlutterAppAotTask = project.tasks.create(name: &#34;packLibs${FLUTTER_BUILD_PREFIX}${variant.name.capitalize()}&#34;, type: Jar) {

// 3. 将第2步生成的 libs.jar 文件添加为依赖 
addApiDependencies(project, variant.name, project.files {
    packFlutterAppAotTask
}

// 4. 创建 copyFlutterAssetsTask。
Task copyFlutterAssetsTask = project.tasks.create(
    name: &#34;copyFlutterAssets${variant.name.capitalize()}&#34;,
    type: Copy,
) { ... }

// Flutter 项目可能作为插件编译或子项目编译(分别对应AAR产物集成和源码集成)
//  a) 当作为插件编译时，编译产物为 AAR
//  b) 当作为子项目编译时，编译产物为 APK

// 作为插件编译和作为子项目编译时对 assets 的处理是不一样的
// 第5步和第6步分别对这两种情况进行处理
boolean isUsedAsSubproject = ...

// 5. 处理作为插件编译时的 assets 拷贝
if (!isUsedAsSubproject) {
    return
}

// 6. 处理作为子项目编译时的 assets 拷贝
// Flutter module included as a subproject in add to app.
Project appProject = project.rootProject.findProject(&#39;:app&#39;)
appProject.afterEvaluate { ... }
</code></pre></td></tr></table>
</div>
</div><p><code>FlutterTask</code> 继承自 <code>BaseFlutterTask</code>。<code>BaseFlutterTask</code> 实际是对 <code>flutter build</code> 命令的包装，具体包装过程可以参数 <a href="https://github.com/flutter/flutter/blob/master/packages/flutter_tools/gradle/flutter.gradle#L819" target="_blank" rel="noopener noreffer">BaseFlutterTask.buildBundle()</a>。</p>
<h3 id="configureplugins">configurePlugins</h3>
<p>再来看 <code>configurePlugins()</code> 如何配置插件依赖。仍然分两种情况处理：源码集成和产物集成。代码如下：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">/**
 * Configures the Flutter plugin dependencies.
 *
 * The plugins are added to pubspec.yaml. Then, upon running `flutter pub get`,
 * the tool generates a `.flutter-plugins` file, which contains a 1:1 map to each plugin location.
 * Finally, the project&#39;s `settings.gradle` loads each plugin&#39;s android directory as a subproject.
 */
private void configurePlugins() {
    // 第1种情况，源码集成
    // 配置源码集成时的插件
    if (!buildPluginAsAar()) {
        // 1. 将 plugin 工程添加为 Android 工程的依赖
        getPluginList().each this.&amp;configurePluginProject
        // 2. 将 plugin 工程的依赖添加为 Android 工程的依赖
        getPluginDependencies().each this.&amp;configurePluginDependencies
        return
    }
    // 第2种情况，产物集成
    // 配置产物集成时的插件
    
    // 1. 将 plugin 工程的编译输出目录添加为 Android 工程的 maven 库
    project.repositories {
        maven {
            url &#34;${getPluginBuildDir()}/outputs/repo&#34;
        }
    }
    // 2. 将 plugin AAR 产物添加为 Android 工程的依赖
    getPluginList().each { pluginName, pluginPath -&gt;
        configurePluginAar(pluginName, pluginPath, project)
    }
}
</code></pre></td></tr></table>
</div>
</div><p>另外，注释中提到了几个很重要的信息：</p>
<blockquote>
<p>插件在 pubspec.yaml 中添加。当运行 <code>flutter pub get</code> 命令时，工具会生成 <code>.flutter-plugins</code> 和 <code>.flutter-plugins-dependencies</code> 文件。<code>.flutter-plugins</code> 包含每个插件的位置，<code>.flutter-plugins-dependencies</code> 包含每个插件的依赖项</p>
<p>Android 项目的 <code>settings.gradle</code> 文件会加载每个插件为子工程</p>
</blockquote>
<p>以我们的项目为例。<code>.flutter-plugins</code> 文件内容如下：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback"># This is a generated file; do not edit or check into version control.
flutter_integration=/Users/abc/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_integration-0.0.1/
flutter_mmkv_cache=/Users/abc/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_mmkv_cache-0.0.2/
path_provider=/Users/abc/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.3.0/
sensors=/Users/abc/flutter/.pub-cache/hosted/pub.dartlang.org/sensors-0.4.1+8/
sqflite=/Users/abc/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.1.7+1/
</code></pre></td></tr></table>
</div>
</div><p>该项目在 Android Studio 中看到的工程结构如下：</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg"
        title="-w249" /></p>
<h2 id="添加-flutter-dependency">添加 Flutter Dependency</h2>
<p><code>apply()</code> 的另一个要点是添加 Flutter 依赖，由 <code>addFlutterDependencies()</code> 实现。相比添加 Flutter Task，添加 Flutter 依赖则简单得多。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">class FlutterPlugin implements Plugin&lt;Project&gt; {
    @Override
    void apply(Project project) {
        ...   
        project.android.buildTypes.each this.&amp;addFlutterDependencies
        project.android.buildTypes.whenObjectAdded this.&amp;addFlutterDependencies
    }


    /**
     * addFlutterDependencies() 方法为 Flutter 工程添加 embedding 和 libflutter.so 依赖 
     *
     * Adds the dependencies required by the Flutter project.
     * This includes:
     *    1. The embedding
     *    2. libflutter.so
     */
    void addFlutterDependencies(buildType) {
        String flutterBuildMode = buildModeFor(buildType)
        if (!supportsBuildMode(flutterBuildMode)) {
            return
        }
        // 1. 添加 Flutter 引擎仓库，默认使用 MAVEN_REPO 
        // MAVEN_REPO 仓库地址 http://download.flutter.io
        String repository = useLocalEngine()
            ? project.property(&#39;local-engine-repo&#39;)
            : MAVEN_REPO

        project.rootProject.allprojects {
            repositories {
                maven {
                    url repository
                }
            }
        }
        // 2. 添加 embedding 依赖
        // Add the embedding dependency.
        addApiDependencies(project, buildType.name,
                &#34;io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion&#34;)

        ...
        platforms.each { platform -&gt;
            String arch = PLATFORM_ARCH_MAP[platform].replace(&#34;-&#34;, &#34;_&#34;)
            // 3. 添加 libflutter.so 依赖
            // Add the `libflutter.so` dependency.
            addApiDependencies(project, buildType.name,
                    &#34;io.flutter:${arch}_$flutterBuildMode:$engineVersion&#34;)
        }
    }
}
</code></pre></td></tr></table>
</div>
</div><h1 id="实践">实践</h1>
<p>通过看 <code>buid.gradle</code> 和 <code>flutter.gradle</code> 源码，我们对 Flutter 如何集成到 Android 项目中有一定的了解了。现在结合两个实例来加深理解，这里以一个编译失败问题和 so 加载失败问题为例。</p>
<h2 id="编译失败-cause-assert-appproject--null">编译失败 Cause: assert appProject != null</h2>
<p>Flutter 1.12.13+hotfix.5 有一个编译失败的 <a href="https://github.com/flutter/flutter/issues/42214" target="_blank" rel="noopener noreffer">Issue #42214</a>，错误日志如下：</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15843459718378.jpg"
        title="企业微信截图_d5221a9a-5eea-4c5d-9c8b-8f99449e06" /></p>
<p>问题来源：这个问题实际上来自 <code>flutter.gradle</code> 脚本中的一处 bug， 见<a href="https://github.com/flutter/flutter/pull/41333/files" target="_blank" rel="noopener noreffer">Pull #41333</a>
问题分析：<code>addFlutterTasks()</code> 方法中第4步存在硬编码问题，<a href="https://github.com/flutter/flutter/blob/master/packages/flutter_tools/gradle/flutter.gradle#L724" target="_blank" rel="noopener noreffer">默认所有的 app module 名为 <code>app</code></a>。实际项目中 app module 名很可能不是 <code>app</code>，所以断言失败，导致集成 Flutter 后编译出错</p>
<p>解决办法：要么将 app module 改名为 <code>app</code>，要么给本地的 <code>flutter.gradle</code> 打上如下补丁。注意要将 <code>IGame</code> 替换成实际项目名。</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg"
        title="-w824" /></p>
<h2 id="找不到-libflutterso-或-libappso">找不到 <code>libflutter.so</code> 或 <code>libapp.so</code></h2>
<p>一些年代比较久远的 Android 项目中，so 往往放在 <code>lib/armeabi</code> 目录。</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg"
        title="-w322" /></p>
<p>而 Flutter 的 AOT 产物只支持 <code>x86_64</code>、 <code>armeabi-v7a</code> 和 <code>arm64-v8a</code> 三种架构。另外，<strong>Flutter 的构建流程默认将会将 so 文件打包到对应的目录中</strong>，</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15837916714301.jpg"
        title="-w323" />
所以会出现找不到 <code>libflutter.so</code> 的问题。一种简单而粗暴的解决方案见 <a href="https://tech.meituan.com/2018/08/09/waimai-flutter-practice.html" target="_blank" rel="noopener noreffer">Flutter原理与实践 - 美团技术团队</a>。</p>
<p>Flutter 构建流程中 <code>packFlutterAppAotTask</code> 会将生成的 <code>app.so</code> 移动并重命名为 <code>lib/&lt;abi&gt;/libapp.so</code>。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">Task packFlutterAppAotTask = project.tasks.create(
  name: &#34;packLibs${FLUTTER_BUILD_PREFIX}${variant.name.capitalize()}&#34;, type: Jar) {
    destinationDir libJar.parentFile
    archiveName libJar.name
    dependsOn compileTask
    targetPlatforms.each { targetPlatform -&gt;
        String abi = PLATFORM_ARCH_MAP[targetPlatform]
        from(&#34;${compileTask.intermediateDir}/${abi}&#34;) {
            include &#34;*.so&#34;
            // Move `app.so` to `lib/&lt;abi&gt;/libapp.so`
            rename { String filename -&gt;
                return &#34;lib/${abi}/lib${filename}&#34;
            }
        }
    }
}
</code></pre></td></tr></table>
</div>
</div><p>修改一：注意这里的 <code>&lt;abi&gt;</code> 只支持上述提到的三种架构，并不包括 <code>armeabi</code>。我们可以修改 <code>packFlutterAppAotTask</code>，修改后将 <code>app.so</code> 移动并重命名为 <code>lib/armeabi/libapp.so</code> 的目的。</p>
<p>修改二：修改原始的 embedding jar 包(<code>libflutter.so</code> 从原始的 <code>lib/armeabi-v7a</code> 移到 <code>lib/armeabi</code> 目录)，并在 <code>gradle.properties</code> 中提供 <code>local-engine-repo</code>，将其指向修改后的 embedding jar 包。具体见 <a href="https://github.com/flutter/flutter/blob/master/packages/flutter_tools/gradle/flutter.gradle#L198" target="_blank" rel="noopener noreffer">addFlutterDependencies()</a></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">/**
 * Adds the dependencies required by the Flutter project.
 * This includes:
 *    1. The embedding
 *    2. libflutter.so
 */
void addFlutterDependencies(buildType) {
    String flutterBuildMode = buildModeFor(buildType)
    if (!supportsBuildMode(flutterBuildMode)) {
        return
    }
    String repository = useLocalEngine()
        ? project.property(&#39;local-engine-repo&#39;)
        : MAVEN_REPO

    project.rootProject.allprojects {
        repositories {
            maven {
                url repository
            }
        }
    }
}
</code></pre></td></tr></table>
</div>
</div><h1 id="参考">参考</h1>
<p><a href="https://flutter.dev/docs/development/add-to-app/android/project-setup" target="_blank" rel="noopener noreffer">Integrate a Flutter module into your Android project - Flutter</a></p>
<p><a href="https://tech.youzan.com/you-zan-flutter-hun-bian-fang-an/" target="_blank" rel="noopener noreffer">有赞 Flutter 混编方案</a></p></div><div class="post-footer" id="post-footer">
    <div class="post-info">
        <div class="post-info-line">
            <div class="post-info-mod">
                <span>更新于 2021-07-31</span>
            </div>
            <div class="post-info-license"></div>
        </div>
        <div class="post-info-line">
            <div class="post-info-md"></div>
            <div class="post-info-share">
                <span><a href="javascript:void(0);" title="分享到 Twitter" data-sharer="twitter" data-url="https://luckly.work/flutter%E5%BA%94%E7%94%A8%E9%9B%86%E6%88%90%E6%B5%85%E6%9E%90/" data-title="《Flutter应用集成浅析》" data-hashtags="flutter"><i class="fab fa-twitter fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Facebook" data-sharer="facebook" data-url="https://luckly.work/flutter%E5%BA%94%E7%94%A8%E9%9B%86%E6%88%90%E6%B5%85%E6%9E%90/" data-hashtag="flutter"><i class="fab fa-facebook-square fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Hacker News" data-sharer="hackernews" data-url="https://luckly.work/flutter%E5%BA%94%E7%94%A8%E9%9B%86%E6%88%90%E6%B5%85%E6%9E%90/" data-title="《Flutter应用集成浅析》"><i class="fab fa-hacker-news fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Line" data-sharer="line" data-url="https://luckly.work/flutter%E5%BA%94%E7%94%A8%E9%9B%86%E6%88%90%E6%B5%85%E6%9E%90/" data-title="《Flutter应用集成浅析》"><i data-svg-src="https://cdn.jsdelivr.net/npm/simple-icons@2.14.0/icons/line.svg"></i></a><a href="javascript:void(0);" title="分享到 微博" data-sharer="weibo" data-url="https://luckly.work/flutter%E5%BA%94%E7%94%A8%E9%9B%86%E6%88%90%E6%B5%85%E6%9E%90/" data-title="《Flutter应用集成浅析》" data-image="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png"><i class="fab fa-weibo fa-fw"></i></a></span>
            </div>
        </div>
    </div>

    <div class="post-info-more">
        <section class="post-tags"><i class="fas fa-tags fa-fw"></i>&nbsp;<a href="/tags/flutter/">flutter</a></section>
        <section>
            <span><a href="javascript:void(0);" onclick="window.history.back();">返回</a></span>&nbsp;|&nbsp;<span><a href="/">主页</a></span>
        </section>
    </div>

    <div class="post-nav"><a href="/flutter-sizedoverflowbox-%E7%AE%80%E4%BB%8B%E5%8F%8A%E6%A1%88%E4%BE%8B/" class="prev" rel="prev" title="《Flutter SizedOverflowBox 简介及案例》"><i class="fas fa-angle-left fa-fw"></i>《Flutter SizedOverflowBox 简介及案例》</a>
            <a href="/futurebuilder%E4%B8%8Estreambuilder/" class="next" rel="next" title="《FutureBuilder与StreamBuilder》">《FutureBuilder与StreamBuilder》<i class="fas fa-angle-right fa-fw"></i></a></div>
</div>
</article></div>
            </main><footer class="footer">
        <div class="footer-container"><div class="footer-line">由 <a href="https://gohugo.io/" target="_blank" rel="noopener noreffer" title="Hugo 0.79.1">Hugo</a> 强力驱动 | 主题 - <a href="https://github.com/dillonzq/LoveIt" target="_blank" rel="noopener noreffer" title="LoveIt 0.2.10"><i class="far fa-kiss-wink-heart fa-fw"></i> LoveIt</a>
                </div><div class="footer-line"><i class="far fa-copyright fa-fw"></i><span itemprop="copyrightYear">2021</span><span class="author" itemprop="copyrightHolder">&nbsp;<a href="/" target="_blank">早起的年轻人</a></span>&nbsp;|&nbsp;<span class="license"><a rel="license external nofollow noopener noreffer" href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank">CC BY-NC 4.0</a></span></div>
        </div>
    </footer></div>

        <div id="fixed-buttons"><a href="#" id="back-to-top" class="fixed-button" title="回到顶部">
                <i class="fas fa-arrow-up fa-fw"></i>
            </a><a href="#" id="view-comments" class="fixed-button" title="查看评论">
                <i class="fas fa-comment fa-fw"></i>
            </a>
        </div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/cookieconsent@3.1.1/build/cookieconsent.min.css"><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/smooth-scroll@16.1.3/dist/smooth-scroll.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/autocomplete.js@0.37.1/dist/autocomplete.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/algoliasearch@4.2.0/dist/algoliasearch-lite.umd.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lazysizes@5.2.2/lazysizes.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/clipboard@2.0.6/dist/clipboard.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/sharer.js@0.4.0/sharer.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/cookieconsent@3.1.1/build/cookieconsent.min.js"></script><script type="text/javascript">window.config={"code":{"copyTitle":"复制到剪贴板","maxShownLines":10},"comment":{},"cookieconsent":{"content":{"dismiss":"同意","link":"了解更多","message":"本网站使用 Cookies 来改善您的浏览体验."},"enable":true,"palette":{"button":{"background":"#f0f0f0"},"popup":{"background":"#1aa3ff"}},"theme":"edgeless"},"search":{"algoliaAppID":"PASDMWALPK","algoliaIndex":"index.zh-cn","algoliaSearchKey":"b42948e51daaa93df92381c8e2ac0f93","highlightTag":"em","maxResultLength":10,"noResultsFound":"没有找到结果","snippetLength":50,"type":"algolia"}};</script><script type="text/javascript" src="/js/theme.min.js"></script></body>
</html>
